/*_____________________________________________________________________________
||
|| STM32 Baremetal Driver: AFIO
||
|| Jinfeng Zhuang, 2024.W18
||
|| Additional Feature: SWIP wrapper
||_____________________________________________________________________________
*/

typedef volatile unsigned int VU32;

typedef struct
{
    VU32 CRL;    // PIN 0-7: mode = input, output 10/2/50MHz; config = input(analog, float, pullup/down) output(push/drain)
    VU32 CRH;    // PIN 8-15: same as CRL
    VU32 IDR;    // PIN 0-15: High/Low
    VU32 ODR;    // PIN 0-15: High/Low
    VU32 BSRR;   // Write ONLY, Atomic bit set/reset as ODR
    VU32 BRR;    // Write ONLY
    VU32 LCKR;   // Each bit lock the CRL or CRH
} GPIO_TypeDef;

// PP: Push-Pull, Output ONLY, like PWM
// OD: I2C, SPI, Input/Output
static void afio_config_output(U32 base, U32 port, U32 pin, U32 pp)
{
    GPIO_TypeDef* GPIOx = (GPIO_TypeDef*)base;
    U32           tmp;
    U32           mode = 0x3;   // Default is Output-50MHz

    if (pp)
    {
        mode |= 0x8;
    }
    else
    {
        mode |= 0xC;
    }

    if (pin < 8)
    {
        tmp = GPIOx->CRL;

        tmp &= 0xF << (pin * 4);
        tmp |= mode << (pin * 4);

        GPIOx->CRL = tmp;
    }
    else
    {
        tmp = GPIOx->CRH;

        tmp &= 0xF << (pin * 4);
        tmp |= mode << (pin * 4);

        GPIOx->CRH = tmp;
    }
}

/*_____________________________________________________________________________
||
|| Wrapper of SWIP
||
|| Include Port related macros.
|| Self compile code, if user want use it, redefine the macros.
||
*/

enum SWIP_CMD
{
    SWIP_CMD_BASE,
	IOMUX_CMD_AFIO,
};

// Support GPIOA/B/C/D/E/F/G/H
static U32 reg_base[8];

U32 event_handler_soc_afio(U32 index, U32 cmd, U32 param1, U32 param2)
{
    U32 port  = (param1 >> 16) & 0xFF;
    U32 pin   = param1 & 0xFF;
    U32 value = param2;

    switch (cmd)
    {
    case SWIP_CMD_BASE:
        reg_base[index] = param1;
        break;
    case IOMUX_CMD_AFIO:
		afio_config_output(reg_base[index], port, pin, value);
		break;
    }
}